/**
 * v-dialogDrag 弹窗拖拽
 * Copyright (c) 2019 ruoyi
 * Enhanced for touch support and cleanup
 */

// Helper function to get clientX/clientY from mouse or touch events
function getClientCoordinates(event) {
  if (event.touches && event.touches.length) {
    // For touch events, use the first touch point
    return { x: event.touches[0].clientX, y: event.touches[0].clientY };
  }
  // For mouse events
  return { x: event.clientX, y: event.clientY };
}

// The getBaseTop function is not implemented, so marginTop behavior might be unexpected if uncommented
// function getBaseTop(el){
//   debugger
//   // Example: return '100px'; or calculate dynamically
// }

export default {
  bind(el, binding, vnode, oldVnode) {
    const value = binding.value;
    if (value === false) return; // Allow disabling the directive with v-dialog-drag="false"

    const dialogHeaderEl = el.querySelector('.el-dialog__header');
    const dragDom = el.querySelector('.el-dialog');

    if (!dialogHeaderEl || !dragDom) {
      console.warn('v-dialogDrag: Could not find .el-dialog__header or .el-dialog element.');
      return;
    }

    dialogHeaderEl.style.cursor = 'move';

    // Get initial styles
    const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null);

    // Ensure the dialog is absolutely positioned for dragging
    // ElementUI dialogs are usually fixed, but absolute positioning is better for custom dragging
    // if you are not using the built-in fullscreen or other conflicting features.
    if (sty.position !== 'absolute' && sty.position !== 'fixed') {
      dragDom.style.position = 'absolute'; // Or 'fixed' if you prefer viewport-relative
    }

    // Initial horizontal centering (ElementUI dialogs are often centered by default)
    // This ensures it's centered if position was changed or not initially centered.
    // If dragDom is already centered, this might be redundant but generally safe.
    let initialWidth = dragDom.style.width;
    if (initialWidth.includes('%')) {
      initialWidth = +document.body.clientWidth * (+initialWidth.replace(/\%/g, '') / 100);
    } else {
      initialWidth = +initialWidth.replace(/\px/g, '');
    }
    // Only set left if it's not already set or if you want to force centering
    // ElementUI dialogs are usually centered with margin: 0 auto or top/left transforms
    // If you set position: absolute, you might need to set left/top.
    // dragDom.style.left = `${(document.body.clientWidth - initialWidth) / 2}px`;
    // If ElementUI dialog is 'fixed' and centered by default (top: 15vh, left: 50%, transform: translateX(-50%)),
    // then making it 'absolute' will require explicit top/left.
    // Let's assume ElementUI handles initial centering well, and this directive primarily adds dragging.
    // If the dialog is NOT centered by default after setting to absolute, uncomment and adjust:

    /*if (sty.position === 'absolute') { // Only if we forced it to absolute
      if (!sty.left || sty.left === 'auto' || sty.left === '0px') { // And it's not already positioned
      }
      // Element UI dialogs usually have `top: 15vh;`. If changing to `absolute`, this might be lost.
      // If `top` becomes `auto` or `0px`, you might want to set a default:
      if (!sty.top || sty.top === 'auto' || sty.top === '0px') {
        // dragDom.style.top = '15vh'; // A common default for Element UI dialogs
      }

    }*/

    
    dragDom.style.left = `${(document.body.clientWidth - initialWidth) / 2}px`;




    // Commented out marginTop logic from original, as getBaseTop is not implemented
    // dragDom.style.marginTop = value === true ? getBaseTop(el) : value;
    // dragDom.style.marginTop = '0px';

    let disX, disY, currentStyL, currentStyT;

    const handleDragStart = (e) => {
      // Prevent text selection during drag for mouse events
     /* if (e.type === 'mousedown') {
        e.preventDefault();
      }*/
      // For touch events, `passive: true` on listener means preventDefault here might not work as expected
      // but we mainly need it for `touchmove`.

      const coords = getClientCoordinates(e);
      disX = coords.x - dialogHeaderEl.offsetLeft; // offsetLeft relative to offsetParent
      disY = coords.y - dialogHeaderEl.offsetTop;  // offsetTop relative to offsetParent

      // Recalculate current left/top numeric values from computed style
      // This is important if the dialog was moved by other means or if styles changed
      const currentSty = dragDom.currentStyle || window.getComputedStyle(dragDom, null);
      if (currentSty.left.includes('%')) {
        currentStyL = +document.body.clientWidth * (+currentSty.left.replace(/\%/g, '') / 100);
        currentStyT = +document.body.clientHeight * (+currentSty.top.replace(/\%/g, '') / 100);
      } else {
        currentStyL = +parseFloat(currentSty.left.replace(/\px/g, '')) || 0;
        currentStyT = +parseFloat(currentSty.top.replace(/\px/g, '')) || 0;
      }

      document.addEventListener('mousemove', handleDragMove);
      document.addEventListener('mouseup', handleDragEnd);
      // For touch, use passive: false on move to allow preventDefault
      document.addEventListener('touchmove', handleDragMove, { passive: false });
      document.addEventListener('touchend', handleDragEnd);
      document.addEventListener('touchcancel', handleDragEnd); // Handle interruption
    };

    const handleDragMove = (e) => {
      // Prevent page scrolling when dragging on touch devices
      if (e.type === 'touchmove') {
        e.preventDefault();
      }

      const coords = getClientCoordinates(e);
      let l = coords.x - disX;
      let t = coords.y - disY;

      // Original boundary check (optional, can be made more robust)
      if (coords.y < 20 && e.type.startsWith('mouse')) { // Original check was for mouse only
        // For touch, you might want a similar check or different behavior
        // Example: t = Math.max(t, 20 - disY - currentStyT); // clamp top
        return; // Or clamp: t = 20 - disY;
      }
      if (coords.y < 0) { // Simpler general top boundary
        t = -disY; // Prevent going above viewport top if disY is based on header's position within dialog
                   // Better: t = -currentStyT (to make dialog top align with viewport top 0)
                   // Or based on dragDom.offsetTop relative to document:
                   // t = -dragDom.getBoundingClientRect().top + currentStyT
      }


      // Combine calculated movement with the style's starting point
      let finalL = l + currentStyL;
      let finalT = t + currentStyT;

      // Add more robust boundary checks (optional)
      // const minLeft = 0;
      // const maxLeft = document.body.clientWidth - dragDom.offsetWidth;
      // const minTop = 0;
      // const maxTop = document.body.clientHeight - dragDom.offsetHeight;
      // finalL = Math.max(minLeft, Math.min(finalL, maxLeft));
      // finalT = Math.max(minTop, Math.min(finalT, maxTop));


      dragDom.style.left = `${finalL}px`;
      dragDom.style.top = `${finalT}px`;
    };

    const handleDragEnd = (e) => {
      document.removeEventListener('mousemove', handleDragMove);
      document.removeEventListener('mouseup', handleDragEnd);
      document.removeEventListener('touchmove', handleDragMove);
      document.removeEventListener('touchend', handleDragEnd);
      document.removeEventListener('touchcancel', handleDragEnd);
    };

    // Add event listeners to the dialog header
    dialogHeaderEl.addEventListener('mousedown', handleDragStart);
    dialogHeaderEl.addEventListener('touchstart', handleDragStart, { passive: true }); // Can be passive for start

    // Store handlers on el for cleanup in unbind
    el._dragData = {
      dialogHeaderEl,
      handleDragStart,
      // handleDragMove and handleDragEnd are bound to document, will be removed by handleDragEnd itself
      // but good to have a reference if unbind needs to force remove them.
      handleDragMove,
      handleDragEnd
    };
  },

  unbind(el, binding, vnode, oldVnode) {
    if (el._dragData) {
      const { dialogHeaderEl, handleDragStart, handleDragMove, handleDragEnd } = el._dragData;
      dialogHeaderEl.removeEventListener('mousedown', handleDragStart);
      dialogHeaderEl.removeEventListener('touchstart', handleDragStart);

      // Ensure document listeners are removed if component is destroyed mid-drag
      document.removeEventListener('mousemove', handleDragMove);
      document.removeEventListener('mouseup', handleDragEnd);
      document.removeEventListener('touchmove', handleDragMove);
      document.removeEventListener('touchend', handleDragEnd);
      document.removeEventListener('touchcancel', handleDragEnd);

      delete el._dragData; // Clean up
    }
  }
};